/**
  ****************************(C) COPYRIGHT 2019 DJI****************************
  * @file       remote_control.c/h
  * @brief      遥控器处理，遥控器是通过类似SBUS的协议传输，利用DMA传输方式节约CPU
  *             资源，利用串口空闲中断来拉起处理函数，同时提供一些掉线重启DMA，串口
  *             的方式保证热插拔的稳定性。
  * @note       该任务是通过串口中断启动，不是freeRTOS任务
  * @history
  *  Version    Date            Author          Modification
  *  V1.0.0     Dec-26-2018     RM              1. done
  *  V1.0.0     Nov-11-2019     RM              1. support development board tpye c
  *
  @verbatim
  ==============================================================================

  ==============================================================================
  @endverbatim
  ****************************(C) COPYRIGHT 2019 DJI****************************
  */

#include "remote_control.h"

#include "main.h"

#include "bsp_usart.h"
#include "string.h"

#include "detect_task.h"

#include "config.h"


//遥控器出错数据上限
#define RC_CHANNAL_ERROR_VALUE 700

extern UART_HandleTypeDef huart3;
extern DMA_HandleTypeDef hdma_usart3_rx;


//取正函数
static int16_t RC_abs(int16_t value);
/**
  * @brief          remote control protocol resolution
  * @param[in]      sbus_buf: raw data point
  * @param[out]     rc_ctrl: remote control data struct point
  * @retval         none
  */
/**
  * @brief          遥控器协议解析
  * @param[in]      sbus_buf: 原生数据指针
  * @param[out]     rc_ctrl: 遥控器数据指
  * @retval         none
  */
static void sbus_to_rc(volatile const uint8_t *sbus_buf, RC_ctrl_t *rc_ctrl);

//remote control data 
//遥控器控制变量
RC_ctrl_t rc_ctrl;
//接收原始数据，为18个字节，给了36个字节长度，防止DMA传输越界
static uint8_t sbus_rx_buf[2][SBUS_RX_BUF_NUM];


/**
  * @brief          remote control init
  * @param[in]      none
  * @retval         none
  */
/**
  * @brief          遥控器初始化
  * @param[in]      none
  * @retval         none
  */
void remote_control_init(void)
{
    RC_Init(sbus_rx_buf[0], sbus_rx_buf[1], SBUS_RX_BUF_NUM);
}
/**
  * @brief          get remote control data point
  * @param[in]      none
  * @retval         remote control data point
  */
/**
  * @brief          获取遥控器数据指针
  * @param[in]      none
  * @retval         遥控器数据指针
  */
const RC_ctrl_t *get_remote_control_point(void)
{
    return &rc_ctrl;
}

//判断遥控器数据是否出错，
uint8_t RC_data_is_error(void)
{
    //使用了go to语句 方便出错统一处理遥控器变量数据归零
    if (RC_abs(rc_ctrl.rc.ch[0]) > RC_CHANNAL_ERROR_VALUE)
    {
        goto error;
    }
    if (RC_abs(rc_ctrl.rc.ch[1]) > RC_CHANNAL_ERROR_VALUE)
    {
        goto error;
    }
    if (RC_abs(rc_ctrl.rc.ch[2]) > RC_CHANNAL_ERROR_VALUE)
    {
        goto error;
    }
    if (RC_abs(rc_ctrl.rc.ch[3]) > RC_CHANNAL_ERROR_VALUE)
    {
        goto error;
    }
    if (rc_ctrl.rc.ch[6] == 0)
    {
        goto error;
    }
    if (rc_ctrl.rc.ch[7] == 0)
    {
        goto error;
    }
    return 0;

error://有修改，需要验证
    rc_ctrl.rc.ch[0] = 0;
    rc_ctrl.rc.ch[1] = 0;
    rc_ctrl.rc.ch[2] = 0;
    rc_ctrl.rc.ch[3] = 0;
    rc_ctrl.rc.ch[4] = 0;
    rc_ctrl.rc.ch[5] = 0;
    rc_ctrl.rc.ch[6] = 0;
    rc_ctrl.rc.ch[7]=0;
    rc_ctrl.mouse.x = 0;
    rc_ctrl.mouse.y = 0;
    rc_ctrl.mouse.z = 0;
    rc_ctrl.mouse.press_l = 0;
    rc_ctrl.mouse.press_r = 0;
    rc_ctrl.key.v = 0;
    return 1;
}

void slove_RC_lost(void)
{
    RC_restart(SBUS_RX_BUF_NUM);
}
void slove_data_error(void)
{
    RC_restart(SBUS_RX_BUF_NUM);
}

//串口中断
void USART3_IRQHandler(void)
{
    if(huart3.Instance->SR & UART_FLAG_RXNE)//接收到数据
    {
        __HAL_UART_CLEAR_PEFLAG(&huart3);
    }
    else if(USART3->SR & UART_FLAG_IDLE)
    {
        static uint16_t this_time_rx_len = 0;

        __HAL_UART_CLEAR_PEFLAG(&huart3);

        if ((hdma_usart3_rx.Instance->CR & DMA_SxCR_CT) == RESET)
        {
            /* Current memory buffer used is Memory 0 */

            //disable DMA
            //失效DMA
            __HAL_DMA_DISABLE(&hdma_usart3_rx);

            //get receive data length, length = set_data_length - remain_length
            //获取接收数据长度,长度 = 设定长度 - 剩余长度
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR;

            //reset set_data_lenght
            //重新设定数据长度
            hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;

            //set memory buffer 1
            //设定缓冲区1
            hdma_usart3_rx.Instance->CR |= DMA_SxCR_CT;
            
            //enable DMA
            //使能DMA
            __HAL_DMA_ENABLE(&hdma_usart3_rx);

            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                sbus_to_rc(sbus_rx_buf[0], &rc_ctrl);
                //记录数据接收时间
                detect_hook(DBUS_TOE);
                #ifndef RC_NO_USART1_OUT
                sbus_to_usart1(sbus_rx_buf[0]);
                #endif
            }
        }
        else
        {
            /* Current memory buffer used is Memory 1 */
            //disable DMA
            //失效DMA
            __HAL_DMA_DISABLE(&hdma_usart3_rx);

            //get receive data length, length = set_data_length - remain_length
            //获取接收数据长度,长度 = 设定长度 - 剩余长度
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart3_rx.Instance->NDTR;

            //reset set_data_lenght
            //重新设定数据长度
            hdma_usart3_rx.Instance->NDTR = SBUS_RX_BUF_NUM;

            //set memory buffer 0
            //设定缓冲区0
            DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
            
            //enable DMA
            //使能DMA
            __HAL_DMA_ENABLE(&hdma_usart3_rx);

            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                //处理遥控器数据
                sbus_to_rc(sbus_rx_buf[1], &rc_ctrl);
                //记录数据接收时间
                detect_hook(DBUS_TOE);
                #ifndef RC_NO_USART1_OUT
                sbus_to_usart1(sbus_rx_buf[1]);
                #endif
            }
        }
    }

}

//取正函数
static int16_t RC_abs(int16_t value)
{
    if (value > 0)
    {
        return value;
    }
    else
    {
        return -value;
    }
}
/**
  * @brief          remote control protocol resolution
  * @param[in]      sbus_buf: raw data point
  * @param[out]     rc_ctrl: remote control data struct point
  * @retval         none
  */
/**
  * @brief          遥控器协议解析
  * @param[in]      sbus_buf: 原生数据指针
  * @param[out]     rc_ctrl: 遥控器数据指
  * @retval         none
  */
static void sbus_to_rc(volatile const uint8_t *sbus_buf, RC_ctrl_t *rc_ctrl)
{
    if (sbus_buf == NULL || rc_ctrl == NULL)
    {
        return;
    }
    if(sbus_buf[0]==0x0f)
    {
        rc_ctrl->rc.ch[0] = ((sbus_buf[1] >> 0 | sbus_buf[2] << 8) & 0x07FF); // Channel 1
        rc_ctrl->rc.ch[1] = ((sbus_buf[2] >> 3 | sbus_buf[3] << 5) & 0x07FF); // Channel 2
        rc_ctrl->rc.ch[2] = ((sbus_buf[3] >> 6 | sbus_buf[4] << 2 | sbus_buf[5] << 10) & 0x07FF);// Channel 3
        rc_ctrl->rc.ch[3] = ((sbus_buf[5] >> 1 | sbus_buf[6] << 7) & 0x07FF); // Channel 4
        rc_ctrl->rc.ch[4] = ((sbus_buf[6] >> 4 | sbus_buf[7] << 4) & 0x07FF); // Channel 5 
        rc_ctrl->rc.ch[4] -= RC_CH_VALUE_OFFSET;
        if(rc_ctrl->rc.ch[4]<0) rc_ctrl->rc.ch[4]=RC_SW_UP;
        else if(rc_ctrl->rc.ch[4]==0) rc_ctrl->rc.ch[4]=RC_SW_MID;
        else if(rc_ctrl->rc.ch[4]>0) rc_ctrl->rc.ch[4]=RC_SW_DOWN;                 
        rc_ctrl->rc.ch[5] = ((sbus_buf[7] >> 7 | sbus_buf[8] << 1 | sbus_buf[9] << 9) & 0x07FF); // Channel 6 
        rc_ctrl->rc.ch[5] -= RC_CH_VALUE_OFFSET;
        if(rc_ctrl->rc.ch[5]<0) rc_ctrl->rc.ch[5]=RC_SW_UP;
        else if(rc_ctrl->rc.ch[5]==0) rc_ctrl->rc.ch[5]=RC_SW_MID;
        else if(rc_ctrl->rc.ch[5]>0) rc_ctrl->rc.ch[5]=RC_SW_DOWN ; 
        rc_ctrl->rc.ch[6] = ((sbus_buf[9] >> 2 | sbus_buf[10] << 6) & 0x07FF); // Channel 7 
        rc_ctrl->rc.ch[6] -= RC_CH_VALUE_OFFSET;
        if(rc_ctrl->rc.ch[6]<0) rc_ctrl->rc.ch[6]=RC_SW_UP;
        else if(rc_ctrl->rc.ch[6]==0) rc_ctrl->rc.ch[6]=RC_SW_MID;
        else if(rc_ctrl->rc.ch[6]>0) rc_ctrl->rc.ch[6]=RC_SW_DOWN ; 
        rc_ctrl->rc.ch[7] = ((sbus_buf[10] >> 5 | sbus_buf[11] << 3) & 0x07FF); // Channel 8  
        rc_ctrl->rc.ch[7] -= RC_CH_VALUE_OFFSET; 
        if(rc_ctrl->rc.ch[7]<0) rc_ctrl->rc.ch[7]=RC_SW_UP;
        else if(rc_ctrl->rc.ch[7]==0) rc_ctrl->rc.ch[7]=RC_SW_MID;
        else if(rc_ctrl->rc.ch[7]>0) rc_ctrl->rc.ch[7]=RC_SW_DOWN ;         
        rc_ctrl->mouse.x =  ((sbus_buf[12] | sbus_buf[13] << 8) & 0x07FF);                  
        rc_ctrl->mouse.y =  ((sbus_buf[13] >> 3 | sbus_buf[14] << 5) & 0x07FF);                
        rc_ctrl->mouse.z =  ((sbus_buf[14] >> 6 | sbus_buf[15] << 2 | sbus_buf[16] << 10) & 0x07FF);                
        rc_ctrl->mouse.press_l =  ((sbus_buf[16] >> 1 | sbus_buf[17] << 7) & 0x07FF);                                 
        rc_ctrl->mouse.press_r =  ((sbus_buf[17] >> 4 | sbus_buf[18] << 4) & 0x07FF);             
        rc_ctrl->key.v =  ((sbus_buf[18]>>7|sbus_buf[19]<<1|sbus_buf[20]<<9) & 0x07FF);  
        rc_ctrl->rc.ch[0] -= RC_CH_VALUE_OFFSET;
        rc_ctrl->rc.ch[1] -= RC_CH_VALUE_OFFSET;
        rc_ctrl->rc.ch[2] -= RC_CH_VALUE_OFFSET;
        rc_ctrl->rc.ch[3] -= RC_CH_VALUE_OFFSET;                                
    }
}


/**
  * @brief          send sbus data by usart1, called in usart3_IRQHandle
  * @param[in]      sbus: sbus data, 18 bytes
  * @retval         none
  */
/**
  * @brief          通过usart1发送sbus数据,在usart3_IRQHandle调用
  * @param[in]      sbus: sbus数据, 18字节
  * @retval         none
  */
void sbus_to_usart1(uint8_t *sbus)
{
    static uint8_t usart_tx_buf[20];
    static uint8_t i =0;
    usart_tx_buf[0] = 0xA6;
    memcpy(usart_tx_buf + 1, sbus, 18);
    for(i = 0, usart_tx_buf[19] = 0; i < 19; i++)
    {
        usart_tx_buf[19] += usart_tx_buf[i];
    }
    usart1_tx_dma_enable(usart_tx_buf, 20);
}

